Creating a Simple Client-Server Application in C

In this tutorial, we will create a simple client-server application in C. The server will listen for incoming connections on a specified port, and the client will connect to the server, send a message, and receive a response. This tutorial is aimed at beginners, so we will explain each line of code in detail.

Server Code


// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    const char *hello = "Hello from server";

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // Forcefully attaching socket to the port 8080
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // Forcefully attaching socket to the port 8080
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 3) < 0) {
        perror("listen");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    read(new_socket, buffer, 1024);
    printf("Message from client: %s\n", buffer);
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");

    close(new_socket);
    close(server_fd);
    return 0;
}

Let's break down the server code:

  • #include <stdio.h>: Includes the standard input/output library.
  • #include <stdlib.h>: Includes the standard library for memory allocation, process control, conversions, etc.
  • #include <string.h>: Includes the string handling library.
  • #include <unistd.h>: Includes the POSIX operating system API.
  • #include <arpa/inet.h>: Includes definitions for internet operations.
  • #define PORT 8080: Defines the port number the server will listen on.
  • int main(): The main function where the program execution begins.
  • int server_fd, new_socket;: Declares file descriptors for the server and new socket.
  • struct sockaddr_in address;: Declares a structure to hold the server address.
  • int opt = 1;: Option for setsockopt to reuse the address and port.
  • int addrlen = sizeof(address);: Length of the address structure.
  • char buffer[1024] = {0};: Buffer to store the message from the client.
  • const char *hello = "Hello from server";: Message to send to the client.
  • if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0): Creates a socket and checks for errors.
  • if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))): Sets socket options to reuse the address and port.
  • address.sin_family = AF_INET;: Sets the address family to IPv4.
  • address.sin_addr.s_addr = INADDR_ANY;: Binds the socket to all available interfaces.
  • address.sin_port = htons(PORT);: Sets the port number, converting it to network byte order.
  • if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0): Binds the socket to the specified address and port.
  • if (listen(server_fd, 3) < 0): Listens for incoming connections with a backlog of 3.
  • if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0): Accepts an incoming connection.
  • read(new_socket, buffer, 1024);: Reads the message from the client into the buffer.
  • printf("Message from client: %s\n", buffer);: Prints the message from the client.
  • send(new_socket, hello, strlen(hello), 0);: Sends the hello message to the client.
  • printf("Hello message sent\n");: Prints a confirmation message.
  • close(new_socket);: Closes the new socket.
  • close(server_fd);: Closes the server socket.
  • return 0;: Exits the program.

Client Code


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080

int main() {
    int sock = 0, valread;
    struct sockaddr_in serv_addr;
    char *hello = "Hello from client";
    char buffer[1024] = {0};

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // Convert IPv4 and IPv6 addresses from text to binary form
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }

    send(sock, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    valread = read(sock, buffer, 1024);
    printf("%s\n", buffer);

    return 0;
}

Let's break down the client code:

  • #include <stdio.h>: Includes the standard input/output library.
  • #include <stdlib.h>: Includes the standard library for memory allocation, process control, conversions, etc.
  • #include <string.h>: Includes the string handling library.
  • #include <unistd.h>: Includes the POSIX operating system API.
  • #include <arpa/inet.h>: Includes definitions for internet operations.
  • #define PORT 8080: Defines the port number the client will connect to.
  • int main(): The main function where the program execution begins.
  • int sock = 0, valread;: Declares a socket and a variable to store the number of bytes read.
  • struct sockaddr_in serv_addr;: Declares a structure to hold the server address.
  • char *hello = "Hello from client";: Message to send to the server.
  • char buffer[1024] = {0};: Buffer to store the message from the server.
  • if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0): Creates a socket and checks for errors.
  • serv_addr.sin_family = AF_INET;: Sets the address family to IPv4.
  • serv_addr.sin_port = htons(PORT);: Sets the port number, converting it to network byte order.
  • if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0): Converts the IP address from text to binary form and checks for errors.
  • if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0): Connects to the server and checks for errors.
  • send(sock, hello, strlen(hello), 0);: Sends the hello message to the server.
  • printf("Hello message sent\n");: Prints a confirmation message.
  • valread = read(sock, buffer, 1024);: Reads the message from the server into the buffer.
  • printf("%s\n", buffer);: Prints the message from the server.
  • return 0;: Exits the program.

Compiling and Running the Code

To compile and run the provided C source code files for the ARM64 architecture, follow these steps:


# Compile the server code
gcc -o server server.c

# Compile the client code
gcc -o client client.c

# Run the server
./server

# Run the client in a separate terminal
./client

This will start the server, which listens on port 8080, and the client will connect to the server, send a message, and receive a response.

 

 

Check out some other Bands on Bandcamp.com. Crazy Fingers (Vancouver 1991), Flying Butt Pliers, and Hammy Ham Hands.

Proudly powered by a Text Editor, an Sftp client and some Internet Searches.

2024 dispelled.ca end of file.